      subroutine loop__1_host(cur_dev, loop_ref, r0000m, a, b)
      integer*8 :: cur_dev
      integer*8 :: loop_ref
      real :: r0000m(0:1)
      integer*8 :: a(7), b(7)
      integer*8 :: boundsLow(2), boundsHigh(2), stepsIgnore(2)
      integer :: j, i
      integer*8 :: a0004, a0002, b0004, b0002
      external loop_fill_bounds
      a0002 = a(2)
      a0004 = a(4)
      b0002 = b(2)
      b0004 = b(4)
      call loop_fill_bounds(loop_ref, boundsLow(1), boundsHigh(1), stepsIgnore(1))
      do j = boundsLow(1), boundsHigh(1)
         do i = boundsLow(2), boundsHigh(2)
            r0000m(a0004 + i + a0002 * j) = 0.
            if (i .eq. 1 .or. j .eq. 1 .or. i .eq. 5002 .or. j .eq. 5002) then
               r0000m(b0004 + i + b0002 * j) = 0.
            else
               r0000m(b0004 + i + b0002 * j) = 1. + i + j
            endif
         enddo
      enddo
      end subroutine loop__1_host

      subroutine loop__2_host(cur_dev, loop_ref, r0000m, a, b)
      integer*8 :: cur_dev
      integer*8 :: loop_ref
      real :: r0000m(0:1)
      integer*8 :: a(7), b(7)
      integer*8 :: boundsLow(2), boundsHigh(2), stepsIgnore(2)
      integer :: j, i
      integer*8 :: a0004, a0002, b0004, b0002
      real :: eps
      integer*8  dvm0c0
      parameter (dvm0c0 = 0)
      external loop_fill_bounds, loop_red_init, loop_red_post
      a0002 = a(2)
      a0004 = a(4)
      b0002 = b(2)
      b0004 = b(4)
      call loop_fill_bounds(loop_ref, boundsLow(1), boundsHigh(1), stepsIgnore(1))
      call loop_red_init(loop_ref, dvm0c0, eps, dvm0c0)
      do j = boundsLow(1), boundsHigh(1)
         do i = boundsLow(2), boundsHigh(2)
            eps = max (eps,abs (r0000m(b0004 + i + b0002 * j) - r0000m(a0004 + i + a0002 * j)))
            r0000m(a0004 + i + a0002 * j) = r0000m(b0004 + i + b0002 * j)
         enddo
      enddo
      call loop_red_post(loop_ref, dvm0c0, eps, dvm0c0)
      end subroutine loop__2_host

      subroutine loop__3_host(cur_dev, loop_ref, r0000m, a, b)
      integer*8 :: cur_dev
      integer*8 :: loop_ref
      real :: r0000m(0:1)
      integer*8 :: a(7), b(7)
      integer*8 :: boundsLow(2), boundsHigh(2), stepsIgnore(2)
      integer :: j, i
      integer*8 :: a0004, a0002, b0004, b0002
      external loop_fill_bounds
      a0002 = a(2)
      a0004 = a(4)
      b0002 = b(2)
      b0004 = b(4)
      call loop_fill_bounds(loop_ref, boundsLow(1), boundsHigh(1), stepsIgnore(1))
      do j = boundsLow(1), boundsHigh(1)
         do i = boundsLow(2), boundsHigh(2)
            r0000m(b0004 + i + b0002 * j) = (r0000m(a0004 + (i - 1) + a0002 * j) + r0000m(a0004 + i + a0002 * (j - 1)) + r0000m(a0004 + (i + 1) + a0002 * j) + r0000m(a0004 + i + a0002 * (j + 1))) / 4
         enddo
      enddo
      end subroutine loop__3_host

      program jac
      parameter (l = 5002, itmax = 5000)
      real  eps,maxeps
      real  startt,endt
      external ftcntr,eiof,biof,clfdvm
      integer*8  dvmlf,delobj,arrcpy,tstio,getach,getad,getaf,getal,getai,dopl,endpl,mappl,crtpl,waitsh,strtsh,inssh,crtshg,waitrd,strtrd,insred,crtrg,crtrdf,align,crtda,distr,crtamv,lexit,linit
      integer*8  dvm000(44+4)
      integer*8  a(38),b(38)
      character*12  filenm001
      integer*8  a0004,a0002,b0004,b0002
      common /jacdvm/eps
      integer*8  dvm0c9,dvm0c8,dvm0c7,dvm0c6,dvm0c5,dvm0c4,dvm0c3,dvm0c2,dvm0c1,dvm0c0
      parameter (dvm0c9 = 9,dvm0c8 = 8,dvm0c7 = 7,dvm0c6 = 6,dvm0c5 = 5,dvm0c4 = 4,dvm0c3 = 3,dvm0c2 = 2,dvm0c1 = 1,dvm0c0 = 0)
      integer  i000io(262144)
      real  r000io(262144)
      equivalence (r000io,i000io)
      character  ch000m(0:64)
      logical  l0000m(0:64)
      double precision  d0000m(0:64)
      real  r0000m(0:64)
      integer  i0000m(0:64)
      equivalence (l0000m,d0000m,r0000m,i0000m)
      common /mem000/i0000m
      integer  idvm01
      integer  idvm00

! DVMH declarations
      external init_cuda, loop__1_cuda, loop__2_cuda, loop__3_cuda
      external loop__1_host, loop__2_host, loop__3_host
      external dvmh_init, dvmh_shadow_renew, dvmh_get_actual_scalar, dvmh_get_actual_subarray
      external region_register_subarray, region_register_scalar, region_prepared_for_devices, region_inner_start, region_end
      external loop_insred, loop_set_cuda_block, loop_register_handler, loop_start, loop_end
      integer*8 dvmh_get_actual_edges, region_create, loop_create

      integer*8 DEVICE_TYPE_HOST, DEVICE_TYPE_CUDA
      parameter (DEVICE_TYPE_HOST = 1, DEVICE_TYPE_CUDA = 2)
      integer*8 HANDLER_TYPE_PARALLEL, HANDLER_TYPE_MASTER
      parameter (HANDLER_TYPE_PARALLEL = 1, HANDLER_TYPE_MASTER = 2)
      integer INTENT_IN, INTENT_OUT, INTENT_LOCAL
      parameter (INTENT_IN = 1, INTENT_OUT = 2, INTENT_LOCAL = 4)

      integer clock_rate, clock_start, clock_end
      data filenm001/'jac_gpu.fdv '/
      filenm001(12:12) = char (0)

      dvm000(1) = 10
      dvm000(1) = dvmlf (dvm000(1),filenm001)
      dvm000(1) = dvm0c6
      dvm000(2) = getai (dvm000(1))
      dvm000(3) = getai (i0000m(0))
      dvm000(4) = getal (l0000m(0))
      dvm000(5) = getaf (r0000m(0))
      dvm000(6) = getad (d0000m(0))
      dvm000(7) = getach (ch000m(0))
      dvm000(8) = getai (dvm000(2))
      dvm000(9) = getai (i0000m(1))
      dvm000(10) = getal (l0000m(1))
      dvm000(11) = getaf (r0000m(1))
      dvm000(12) = getad (d0000m(1))
      dvm000(13) = getach (ch000m(1))
      i0000m(0) = 8
      i0000m(1) = 4
      i0000m(2) = 4
      i0000m(3) = 4
      i0000m(4) = 8
      i0000m(5) = 1
      i0000m(10) = 2
      i0000m(11) = 1
      i0000m(12) = 1
      i0000m(13) = 3
      i0000m(14) = 4
      i0000m(15) = 5
      call ftcntr(6,dvm000(2),dvm000(8),i0000m(0),i0000m(10))
      dvm000(1) = linit (dvm0c0)
      dvm000(4) = 2
      dvm000(5) = 1
      dvm000(6) = 0
      dvm000(7) = 0
      dvm000(8) = 5
      dvm000(8) = dvmlf (dvm000(8),filenm001)
      dvm000(8) = l
      dvm000(9) = l
      dvm000(10) = crtamv (dvm0c0,dvm0c2,dvm000(8),dvm0c0)
      dvm000(11) = distr (dvm000(10),dvm0c0,dvm0c2,dvm000(4),dvm000(6))

! Some initializations
      call dvmh_init()
      call init_cuda()

      dvm000(12) = 1
      dvm000(13) = 1
      a(5) = 1
      a(6) = 1
      a(7) = 8
      dvm000(14) = crtda (a(1),dvm0c1,i0000m,dvm0c2, (-(dvm0c3)),dvm000(8),dvm0c0,dvm0c0,dvm000(12),dvm000(12))
      dvm000(15) = 1
      dvm000(16) = 2
      dvm000(17) = 1
      dvm000(18) = 1
      dvm000(19) = 0
      dvm000(20) = 0
      dvm000(21) = align (a(1),dvm000(10),dvm000(15),dvm000(17),dvm000(19))
      dvm000(12) = 1
      dvm000(13) = 2
      dvm000(14) = 1
      dvm000(15) = 1
      dvm000(16) = 0
      dvm000(17) = 0
      dvm000(18) = 6
      dvm000(18) = dvmlf (dvm000(18),filenm001)
      dvm000(18) = l
      dvm000(19) = l
      dvm000(20) = 1
      dvm000(21) = 1
      b(5) = 1
      b(6) = 1
      b(7) = 8
      dvm000(22) = crtda (b(1),dvm0c1,i0000m,dvm0c2, (-(dvm0c3)),dvm000(18),dvm0c0,dvm0c0,dvm000(20),dvm000(20))
      dvm000(23) = align (b(1),a(1),dvm000(12),dvm000(14),dvm000(16))
      dvm000(11) = 10
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      call biof()

!         arrays A and B  with block distribution
      if (tstio () .ne. 0)       print *, '**********  TEST_JACOBI   **********'
      call eiof()
      maxeps = 0.5e-7

! Start synchronous region
      dvm000(45) = region_create(dvm0c0)
! Whole arrays A and B. out(A, B)
      dvm000(46) = -2147483648
      dvm000(47) = -2147483648
      call region_register_subarray(dvm000(45), INTENT_OUT, a, dvm000(46), dvm000(46))
      call region_register_subarray(dvm000(45), INTENT_OUT, b, dvm000(46), dvm000(46))
! Pass bitmask of device types that can be used due to compiler options and region inner limitations
      call region_prepared_for_devices(dvm000(45), ior(DEVICE_TYPE_HOST, DEVICE_TYPE_CUDA))
! Signals start of execution
      call region_inner_start(dvm000(45))

      dvm000(11) = 12
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      b0002 = b(2)
      b0004 = b(4)
      a0002 = a(2)
      a0004 = a(4)
      dvm000(11) = crtpl (dvm0c2)
      dvm000(18) = getai (j)
      dvm000(19) = getai (i)
      dvm000(20) = 1
      dvm000(21) = 1
      dvm000(22) = 1
      dvm000(23) = 1
      dvm000(24) = l
      dvm000(25) = l
      dvm000(26) = 1
      dvm000(27) = 1
      dvm000(28) = 1
      dvm000(29) = 2
      dvm000(30) = 1
      dvm000(31) = 1
      dvm000(32) = (-1)
      dvm000(33) = (-1)
      dvm000(34) = mappl (dvm000(11),a(1),dvm000(28),dvm000(30),dvm000(32),dvm000(18),dvm000(20),dvm000(22),dvm000(24),dvm000(26),dvm000(12),dvm000(14),dvm000(16))
90000 continue
      dvm000(35) = 17
      dvm000(35) = dvmlf (dvm000(35),filenm001)
      dvm000(35) = dopl (dvm000(11))
      if (dvm000(35) .eq. 0)       goto 89999

! Parallel loop
      dvm000(46) = loop_create(dvm000(45), dvm000(11))
! Registering handlers for parallel loop
      call loop_register_handler(dvm000(46), DEVICE_TYPE_HOST, dvm0c0, loop__1_host, dvm0c0, dvm0c3, r0000m, a, b)
      call loop_register_handler(dvm000(46), DEVICE_TYPE_CUDA, dvm0c0, loop__1_cuda, dvm0c0, dvm0c2, a, b)
! Start execution
      call loop_start(dvm000(46))
! Loop end
      call loop_end(dvm000(46))

      goto 90000
89999 continue
      dvm000(36) = 25
      dvm000(36) = dvmlf (dvm000(36),filenm001)
      dvm000(36) = endpl (dvm000(11))

! Compute region ending
      call region_end(dvm000(45))

      call cpu_time(startt)
      call system_clock(count_rate=clock_rate)
      call system_clock(count=clock_start)
      do 2 it = 1,itmax
         eps = 0.

! Register compute region and distributed arrays
         dvm000(45) = region_create(dvm0c0)
! Whole arrays A and B. inout(A, B)
         dvm000(46) = -2147483648
         dvm000(47) = -2147483648
         call region_register_subarray(dvm000(45), ior(INTENT_IN, INTENT_OUT), a, dvm000(46), dvm000(46))
         call region_register_subarray(dvm000(45), ior(INTENT_IN, INTENT_OUT), b, dvm000(46), dvm000(46))
! Scalar variable EPS. out(EPS)
         call region_register_scalar(dvm000(45), INTENT_OUT, eps, dvm0c4)
! Pass bitmask of device types that can be used due to compiler options and region inner limitations
         call region_prepared_for_devices(dvm000(45), ior(DEVICE_TYPE_HOST, DEVICE_TYPE_CUDA))
! Signals start of execution
         call region_inner_start(dvm000(45))

         dvm000(11) = 30
         dvm000(11) = dvmlf (dvm000(11),filenm001)
         a0002 = a(2)
         a0004 = a(4)
         b0002 = b(2)
         b0004 = b(4)
         dvm000(18) = crtrg (dvm0c1,dvm0c1)
         dvm000(36) = 1
         dvm000(37) = 0
         dvm000(38) = crtrdf (dvm0c3,getaf (eps),dvm0c3,dvm000(36),dvm0c0,dvm000(37),dvm0c1)
         dvm000(11) = crtpl (dvm0c2)
         dvm000(19) = getai (j)
         dvm000(20) = getai (i)
         dvm000(21) = 1
         dvm000(22) = 1
         dvm000(23) = 2
         dvm000(24) = 2
         dvm000(25) = l - 1
         dvm000(26) = l - 1
         dvm000(27) = 1
         dvm000(28) = 1
         dvm000(29) = 1
         dvm000(30) = 2
         dvm000(31) = 1
         dvm000(32) = 1
         dvm000(33) = (-1)
         dvm000(34) = (-1)
         dvm000(35) = mappl (dvm000(11),a(1),dvm000(29),dvm000(31),dvm000(33),dvm000(19),dvm000(21),dvm000(23),dvm000(25),dvm000(27),dvm000(12),dvm000(14),dvm000(16))
         dvm000(39) = insred (dvm000(18),dvm000(38),dvm000(11),dvm0c0)
89997    continue
         dvm000(40) = 34
         dvm000(40) = dvmlf (dvm000(40),filenm001)
         dvm000(40) = dopl (dvm000(11))
         if (dvm000(40) .eq. 0)          goto 89996

! Parallel loop
         dvm000(46) = loop_create(dvm000(45), dvm000(11))
         call loop_insred(dvm000(46), dvm000(38))
! Registering handlers for parallel loop
         call loop_register_handler(dvm000(46), DEVICE_TYPE_HOST, dvm0c0, loop__2_host, dvm0c0, dvm0c3, r0000m, a, b)
         call loop_register_handler(dvm000(46), DEVICE_TYPE_CUDA, dvm0c0, loop__2_cuda, dvm0c0, dvm0c2, a, b)
! Setting additional options
         dvm000(47) = 256
         call loop_set_cuda_block(dvm000(46), dvm000(47), dvm0c1, dvm0c1)
! Start execution
         call loop_start(dvm000(46))
! Loop end
         call loop_end(dvm000(46))

         goto 89997
89996    continue
         dvm000(41) = 38
         dvm000(41) = dvmlf (dvm000(41),filenm001)
         dvm000(41) = endpl (dvm000(11))
         dvm000(42) = getaf (eps)
         dvm000(42) = strtrd (dvm000(18))
         dvm000(43) = waitrd (dvm000(18))
         dvm000(44) = delobj (dvm000(18))
         dvm000(11) = 39
         dvm000(11) = dvmlf (dvm000(11),filenm001)
         a0002 = a(2)
         a0004 = a(4)
         b0002 = b(2)
         b0004 = b(4)
         dvm000(11) = crtpl (dvm0c2)
         dvm000(18) = crtshg (dvm0c0)
         dvm000(19) = (-1)
         dvm000(20) = (-1)
         dvm000(21) = inssh (dvm000(18),a(1),dvm000(19),dvm000(19),dvm0c0)

! Update host edge elements
         dvm000(47) = dvmh_get_actual_edges(dvm000(18))

         dvm000(22) = strtsh (dvm000(18))
         dvm000(23) = getai (j)
         dvm000(24) = getai (i)
         dvm000(25) = 1
         dvm000(26) = 1
         dvm000(27) = 2
         dvm000(28) = 2
         dvm000(29) = l - 1
         dvm000(30) = l - 1
         dvm000(31) = 1
         dvm000(32) = 1
         dvm000(33) = 1
         dvm000(34) = 2
         dvm000(35) = 1
         dvm000(36) = 1
         dvm000(37) = (-1)
         dvm000(38) = (-1)
         dvm000(39) = waitsh (dvm000(18))

! Update shadow elements on devices involved into region execution
         call dvmh_shadow_renew(dvm000(45), dvm000(47))

         dvm000(40) = mappl (dvm000(11),b(1),dvm000(33),dvm000(35),dvm000(37),dvm000(23),dvm000(25),dvm000(27),dvm000(29),dvm000(31),dvm000(12),dvm000(14),dvm000(16))
89994    continue
         dvm000(41) = 43
         dvm000(41) = dvmlf (dvm000(41),filenm001)
         dvm000(41) = dopl (dvm000(11))
         if (dvm000(41) .eq. 0)          goto 89993

! Parallel loop
         dvm000(46) = loop_create(dvm000(45), dvm000(11))
! Registering handlers for parallel loop
         call loop_register_handler(dvm000(46), DEVICE_TYPE_HOST, dvm0c0, loop__3_host, dvm0c0, dvm0c3, r0000m, a, b)
         call loop_register_handler(dvm000(46), DEVICE_TYPE_CUDA, dvm0c0, loop__3_cuda, dvm0c0, dvm0c2, a, b)
! Setting additional options
         dvm000(47) = 256
         call loop_set_cuda_block(dvm000(46), dvm000(47), dvm0c1, dvm0c1)
! Start execution
         call loop_start(dvm000(46))
! Loop end
         call loop_end(dvm000(46))

         goto 89994
89993    continue
         dvm000(42) = 47
         dvm000(42) = dvmlf (dvm000(42),filenm001)
         dvm000(42) = endpl (dvm000(11))

! Compute region ending
         call region_end(dvm000(45))

! get_actual(EPS)
         call dvmh_get_actual_scalar(eps)

         dvm000(11) = 49
         dvm000(11) = dvmlf (dvm000(11),filenm001)
         call biof()

         if (tstio () .ne. 0)          print 200, it,eps
         call eiof()
200                  FORMAT(' IT = ',I4, '   EPS = ', E14.7)
!         if (eps .lt. maxeps)          goto 3
2        continue
3     it = 0


! get_actual(B)
      dvm000(45) = -2147483648
      dvm000(46) = -2147483648
      call dvmh_get_actual_subarray(b, dvm000(45), dvm000(45))

      call cpu_time(endt)
      call system_clock(count=clock_end)
      dvm000(11) = 56
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      call biof()
      if (tstio () .ne. 0)       print *, 'time = ',endt - startt,'clock = ', real(clock_end - clock_start) / clock_rate
      call eiof()
      dvm000(11) = 57
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      call biof()
      if (tstio () .ne. 0)       open (unit = 3,file = 'JAC.DAT',form = 'FORMATTED',status = 'UNKNOWN')
      call eiof()
      dvm000(11) = 58
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      call biof()
      do 89991 idvm01 = 0,4999,52
         if (idvm01 + 52 .le. l) then
            dvm000(11) = 52
         else
            dvm000(11) = l - idvm01
         endif
         dvm000(12) = idvm01
         dvm000(13) = (-1)
         dvm000(14) = idvm01 + dvm000(11) - 1
         dvm000(16) = 1
         dvm000(18) = arrcpy (b(1),dvm000(12),dvm000(14),dvm000(16),i000io(1),dvm000(12),dvm000(14),dvm000(16),dvm0c2)
         if (tstio () .ne. 0)          write (unit = 3,fmt = *) (r000io(idvm00), idvm00 = 1,dvm000(11) * l)
89991    continue
      call eiof()
      dvm000(11) = 59
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      call biof()
      if (tstio () .ne. 0)       close (unit = 3)
      call eiof()
      dvm000(11) = 60
      dvm000(11) = dvmlf (dvm000(11),filenm001)
      call clfdvm()
      dvm000(11) = lexit (dvm0c0)
      end

